#include <iostream>
using namespace std;

typedef int Object;

class Iterator {
public:
    Iterator() = default;
    virtual ~Iterator() = default;
    virtual void First() = 0;
    virtual void Next() = 0;
    virtual bool IsDone() = 0;
    virtual Object CurrentItem() = 0;
};

class Aggregate {
public:
    Aggregate() = default;
    virtual ~Aggregate() = default;
    //virtual Iterator* CreateIterator() = 0;
    virtual Object GetItem(int idx) = 0;
    virtual int GetSize() = 0;
};

class ConcreteIterator :public Iterator {
public:
    ConcreteIterator(Aggregate *ag, int idx /* = 0 */){
		_ag = ag;
		_idx = idx;
	}

    void First(){
		_idx = 0;
	}
    void Next(){
		if (_idx < _ag->GetSize()) {
			_idx++;
		}
	}
    bool IsDone(){
		return (_idx == _ag->GetSize());
	}
    Object CurrentItem(){
		return _ag->GetItem(_idx);
	}
private:
    Aggregate* _ag;
    int _idx;
};

// ConcreteIterator::ConcreteIterator(Aggregate *ag, int idx = 0) {
    // _ag = ag;
    // _idx = idx;
// }

// Object ConcreteIterator::CurrentItem() {
    // return _ag->GetItem(_idx);
// }

// void ConcreteIterator::First() {
    // _idx = 0;
// }

// void ConcreteIterator::Next() {
    // if (_idx < _ag->GetSize()) {
        // _idx++;
    // }
// }

// bool ConcreteIterator::IsDone() {
    // return (_idx == _ag->GetSize());
// }

/**********************		Aggregate		*********************/


class ConcreteAggreaget :public Aggregate {
public:
    enum { SIZE = 3 };
    ConcreteAggreaget(){
		for (int i = 0; i < SIZE; i++) {
			_objs[i] = i;
		}
	}
    //Iterator* CreateIterator(){
	//    return new ConcreteIterator(this);
	//}
    Object GetItem(int idx){
		if (idx < this->GetSize()) {
			return _objs[idx];
		}
		else {
			return -1;
		}
	}
    int GetSize() {
		return SIZE;
	}
private:
    Object _objs[SIZE];
};

// ConcreteAggreaget::ConcreteAggreaget() {
    // for (int i = 0; i < SIZE; i++) {
        // _objs[i] = i;
    // }
// }

// Iterator* ConcreteAggreaget::CreateIterator() {
   // return new ConcreteIterator(this);
// }

// Object ConcreteAggreaget::GetItem(int idx) {
    // if (idx < this->GetSize()) {
        // return _objs[idx];
    // }
    // else {
        // return -1;
    // }
// }

// int ConcreteAggreaget::GetSize() {
    // return SIZE;
// }


int main() {
    Aggregate* ag = new ConcreteAggreaget();
    Iterator *it = new ConcreteIterator(ag, 0);
    for (; !(it->IsDone()); it->Next()) {
        cout << it->CurrentItem() << endl;
    }
    delete it;
    delete ag;

    return 0;
}
